

#include "Model.h"
#include "ModelRCMgrIns.h"
#include "Anim.h"
#include "Bone.h"
#include "SkelMeshNode.h"
#include "SkeletonMesh.h"
//#include "CharacterBase.h"

CModel::CModel( /*CCharacterBase* pCharacter,*/const int& iCharacterType,const int& iClass,const int& iIndex ) :
m_iRendMode(0),m_vec4Hit(1.0f,0.0f,1.0f,0.0),
m_iCharType(iCharacterType), m_iClass(iClass),m_iIndex(iIndex),m_fRadius(0),m_fDamagehit(0.0f),m_fDistance(0.0f),
m_vec4Spec(0.6f,0.6f,0.5f,1.0f),m_vec4Diffuse(0.75f,0.75f,0.80f,1.0f),m_iOption(0),m_bSlerpRot(FALSE),m_fRotAngle(0.0f),
m_fShadowMaxX(0.0f),m_fShadowMaxY(0.0f),m_bVisual(TRUE)
, m_pCharacter( NULL )
{
	D3DXMatrixIdentity(&m_matTrans);
	D3DXMatrixIdentity(&m_matRot);
	D3DXMatrixIdentity(&m_matRotOrig);
	D3DXMatrixIdentity(&m_matInterpol);
	Init( );
}

CModel::~CModel(void)
{
	Term();
}

void CModel::Init( )
{
	if (m_iCharType == _MAN || m_iCharType == _WOMEN)
	{
		InitPC();
	}
	else
	{
		InitNPC();
	}

}

void  CModel::InitPC()
{
	CSkeletonMesh* pSkeMesh = new CSkeletonMesh(this,_SMESH_GENERAL,m_iIndex);
	_ModelRCDes des;
	des.iCharType = m_iCharType;
	des.iClass    = m_iClass;
	des.iIndex    = 0;//m_iIndex;

	if (pSkeMesh->InitBone())	
	{
		des.iPartType = _HAND;
		pSkeMesh->AddMesh(&des);
		des.iPartType = _HAIR;
		pSkeMesh->AddMesh(&des);
		des.iPartType = _FOOT;
		pSkeMesh->AddMesh(&des);
		des.iPartType = _CLOCK;
		pSkeMesh->AddMesh(&des);
		des.iPartType = _BODY;
		pSkeMesh->AddMesh(&des);

		m_listSkeletoMesh.Append(pSkeMesh);		
	}
	else
	{
		delete pSkeMesh;
		return;//must have _SMESH_GENERAL
	}
	pSkeMesh = new CSkeletonMesh(this,_SMESH_FACE);
	if (pSkeMesh->InitBone())
	{
		des.iPartType = _FACE;
		pSkeMesh->AddMesh(&des);

		m_listSkeletoMesh.Append(pSkeMesh);
	}
	else
	{
		delete pSkeMesh;
	}
	pSkeMesh = new CSkeletonMesh(this,_SMESH_WEAPON);
	if (pSkeMesh->InitBone())
	{
		des.iPartType = _ARM;
		des.iIndex    = 0;
		pSkeMesh->AddMesh(&des);

		m_listSkeletoMesh.Append(pSkeMesh);
	}
	else
	{
		delete pSkeMesh;
	}

	SetAnim(_SMESH_GENERAL,2,_PlayOpt1,FALSE);


}
void  CModel::InitNPC()
{
	_ModelRCDes des;
	GetNPCRCDesByIndex(des,m_iIndex);
	
	const int iIndexEX = des.iIndex/10;
	des.iIndexEX = des.iIndex - iIndexEX*10;
	des.iIndex = iIndexEX;

	CSkeletonMesh* pSkeMesh = new CSkeletonMesh(this,_SMESH_GENERAL,des.iIndex);
	if (pSkeMesh->InitBone())
	{
		pSkeMesh->AddMesh(&des);
		m_listSkeletoMesh.Append(pSkeMesh);		

		SetAnim(_SMESH_GENERAL,3,_PlayOpt0,FALSE);
	}
	else
	{
		delete pSkeMesh;
	}
}

void CModel::Term()
{
	GDeleteAndRemoveElements(m_listSkeletoMesh);
}

CSkeletonMesh* CModel::AddSkelMesh(const int& iSkelType,const int& iBoneIndex)
{
	CSkeletonMesh* pSkeMesh = GetSkeMeshByType(iSkelType);
	if (pSkeMesh)
	{
		return pSkeMesh;
	}
	pSkeMesh = new CSkeletonMesh(this,_SMESH_GENERAL,m_iIndex);
	_ModelRCDes des;
	des.iCharType = m_iCharType;
	des.iClass    = m_iClass;
	des.iIndex    = iBoneIndex;

	if (pSkeMesh->InitBone())	
	{
		m_listSkeletoMesh.Append(pSkeMesh);		
	}
	else
	{
		delete pSkeMesh;
		pSkeMesh = NULL;
	}
	return pSkeMesh;
}

void CModel::Update(const float& fElapsedTime)
{
	RunRotate(fElapsedTime);
	CSkeletonMesh* pMesh = NULL;
	GPOS pos = m_listSkeletoMesh;
	while (pos)
	{
		pMesh = m_listSkeletoMesh.GetNext(pos);
		pMesh->CheckFrame(fElapsedTime);
	}
}

CSkeletonMesh* CModel::GetSkeMeshByType(const int& iType)
{
	CSkeletonMesh* pMesh = NULL;
	GPOS pos = m_listSkeletoMesh;
	while (pos)
	{
		pMesh = m_listSkeletoMesh.GetNext(pos);
		if (pMesh->GetType() == iType)
		{
			return pMesh;
		}
	}

	return NULL;
}

BOOL CModel::SetTextureFactor(const int& iType,const int& iPartType,const DWORD& dwFactor)
{
	CSkeletonMesh* pSkeMesh = GetSkeMeshByType(iType);
	if (!pSkeMesh)
	{
		return FALSE;
	}

	CSkelMeshNode* pNode = pSkeMesh->GetMeshNodeByType(iPartType);
	if (!pNode)
	{
		return FALSE;
	}

	pNode->SetTextureFactor(dwFactor);
	return TRUE;
}

BOOL CModel::SetAnim(const int& iType, const int& iIndex,const _AniPlayOption& playOpt,const BOOL& bReset,const int& iNameShare)
{
	CSkeletonMesh* pSkeMesh = GetSkeMeshByType(iType);
	if (!pSkeMesh)
	{
		return FALSE;
	}

	_ModelRCDes des;
	des.iCharType = m_iCharType;
	des.iClass    = m_iClass;
	des.iPartType = GetSkAinPartFormMeshType(iType);
	des.iNameShare = iNameShare;
	
	if (m_iCharType >= _NPC)
	{
		des.iIndex = pSkeMesh->m_iIndex;
		des.iIndexEX = iIndex;
	}
	else
	{
		des.iIndex  = iIndex;
	}
	
	
	BOOL bResult = pSkeMesh->SetAnim(&des,playOpt,bReset);
	return bResult;
}

BOOL CModel::ChangeBone(const int& iClass,const int& iType,const int& iBoneIndex)
{
	BOOL bRusult = TRUE;
	if (iType == _SMESH_GENERAL)
	{
		return FALSE;
	}

	if (iClass == m_iClass)
	{
		return bRusult;
	}
	
	m_iClass = iClass;
	CSkeletonMesh* pMesh = GetSkeMeshByType(iType);
	if (pMesh)
	{
		bRusult =  pMesh->ResetBone();
		if (!bRusult)
		{
			m_listSkeletoMesh.RemoveAt(pMesh);
		}
	}
	else
	{
		bRusult =  (NULL == AddSkelMesh(iType,iBoneIndex));
	}

	return bRusult;
}

BOOL CModel::ChangeMesh(const int& iPartType,const int& iIndex,const BOOL& bAdd)
{
	const int iType = GetSkMeshTypeFormMeshPart(iPartType);
	CSkeletonMesh* pSkeMesh = GetSkeMeshByType(iType);
	if (!pSkeMesh)
	{
		return FALSE;
	}
	return pSkeMesh->ChangeMesh(iPartType,iIndex,bAdd)	;
}

BOOL CModel::ChangeMesh(const int& iPartType,const char* pszSkinName,const char* pszTexName,const BOOL& bAdd)
{
	const int iType = GetSkMeshTypeFormMeshPart(iPartType);
	CSkeletonMesh* pSkeMesh = GetSkeMeshByType(iType);
	if (!pSkeMesh)
	{
		return FALSE;
	}
	return pSkeMesh->ChangeMesh(iPartType,pszSkinName,pszTexName,bAdd);
}

void GetDirectionMatrix(const D3DXVECTOR3 &_start,const D3DXVECTOR3 &_des,D3DXMATRIX &mat)
{
	D3DXVECTOR3		start, des;
	start =_start;
	des=_des;
	des.y=start.y;

	D3DXVECTOR3 xdir;
	des=start-des;

	if (des.x==0.0f && des.y==0.0f && des.z==0.0f )
	{
		D3DXMatrixIdentity(&mat);
		return;
	}

	static const D3DXVECTOR3 up(0.0f,1.0f,0.0f);
	D3DXVec3Normalize(&start,&des);
	D3DXVec3Cross(&xdir,&up,&start);
	D3DXVec3Normalize(&xdir,&xdir);
	D3DXVec3Normalize(&start,&start);
	mat._11=xdir.x;
	mat._12=xdir.y;
	mat._13=xdir.z;
	mat._21=up.x;
	mat._22=up.y;
	mat._23=up.z;
	mat._31=start.x;
	mat._32=start.y;
	mat._33=start.z;
}

void CModel::InitRotate(const D3DXVECTOR3 &dest)
{
	D3DXMATRIX mat= m_matRot;
	D3DXVECTOR3 start(m_matTrans._41,0.0f,m_matTrans._43);
	m_bSlerpRot=TRUE;
	D3DXQuaternionRotationMatrix(&m_quaRotSlerpStart,&mat);
	GetDirectionMatrix(start,dest,mat);
	D3DXQuaternionRotationMatrix(&m_quaRotSlerpEnd,&mat);
	m_matInterpol = mat;
	m_fRotAngle=0.0f;

	//char test[150];
	//sprintf( test,"new mat: x = %f, y = %f, z= %f\n", mat._31, mat._32, mat._33);
	//::OutputDebugString( test );
}

void CModel::RunRotate(const float& fElapsedTime)
{	
	if (!m_bSlerpRot)
	{
		return;		
	}

	D3DXQUATERNION out;
	D3DXQuaternionSlerp(&out,&m_quaRotSlerpStart,&m_quaRotSlerpEnd,m_fRotAngle);
	D3DXMatrixRotationQuaternion(&m_matRot,&out);
	m_fRotAngle += fElapsedTime*8;
	if (m_fRotAngle>1.0f)
	{
		m_bSlerpRot = FALSE;
		m_fRotAngle=0.0f;
		D3DXQuaternionSlerp(&out,&m_quaRotSlerpStart,&m_quaRotSlerpEnd,1.0f);
		D3DXMatrixRotationQuaternion(&m_matRot,&out);
	}
}

BOOL CModel::SetAnimEvent(const _AniEventType& eType,const _AniEventFLag& eFlag,const int& iSklType)
{
	BOOL bReult = FALSE;
	CSkeletonMesh* pSkeMesh = GetSkeMeshByType(iSklType);
	if (pSkeMesh)
	{
		bReult =  pSkeMesh->SetEventFlag(eType,eFlag);
	}

	return bReult;
}

void CModel::RunAnimEvent(_AnimEvent* pEvent)
{
	//if ( m_pCharacter != NULL )
	//	m_pCharacter->RunAnimEvent( pEvent );
}

 const D3DXVECTOR3& CModel::GetMeshMax(const int& iParttype)
{
	const int iSkeType = GetSkMeshTypeFormMeshPart(iParttype);
	CSkeletonMesh* pSkeMesh = GetSkeMeshByType(iSkeType);

	CSkelMeshNode* pNode = pSkeMesh->GetMeshNodeByType(iParttype);
	assert(pNode);
	return pNode->GetMax();
}

 const D3DXVECTOR3& CModel::GetMeshMin(const int& iParttype)
{
	const int iSkeType = GetSkMeshTypeFormMeshPart(iParttype);
	CSkeletonMesh* pSkeMesh = GetSkeMeshByType(iSkeType);

	CSkelMeshNode* pNode = pSkeMesh->GetMeshNodeByType(iParttype);
	assert(pNode);
	return pNode->GetMin();
}